package utils

import (
	"encoding/xml"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strings"

	"github.com/prometheus/log"
)

//读取配置，从客户端配置中读取需要的信息
type XMLConf struct {
	XMLName   xml.Name    `xml:"configuration"`
	NameValue []NameValue `xml:"property"`
}

type NameValue struct {
	Name  string `xml:"name"`
	Value string `xml:"value"`
	Final string `xml:"final"`
}

type NameNodeConf struct {
	RpcPort     string //RPC端口
	ServerIP    string //NameNode IP
	NameService string //HDFS的nameservice
	NameNodeID  string //NameNode ID
	HttpsOpen   bool   //是否开启https
	HttpPort    string //http端口
	HttpsPort   string //https端口
}

type DataNodeConf struct {
	RpcPort    string // RPC端口
	ServerIP   string // DataNode IP，如果本机没有DataNode实例则直接panic
	ServerPort string // DataNode Server Por
	HostName   string // DataNode 主机名
	HttpsOpen  bool   // 是否开启https
	HttpPort   string // http端口
	HttpsPort  string // https端口
}

type ResourceManagerConf struct {
	RpcPort          string //RPC端口
	ServerIP         string //ResourceManger IP
	ResourceMangerID string //ResourceManger ID
	HttpsOpen        bool   //是否开启https
	HttpPort         string //http端口
	HttpsPort        string //https端口
}

//用于搜索配置值
func (x *XMLConf) SearchConf(name string) (string, error) {
	for _, v := range x.NameValue {
		//匹配配置项
		if strings.Contains(v.Name, name) {
			return v.Value, nil
		}
	}
	err := errors.New(fmt.Sprintf("Can not find the key: %s.", name))
	return "", err
}

// 读取XML配置文件
func (x *XMLConf) ReadXML(path string) error {
	xmlFile, err := os.Open(path)
	if err != nil {
		log.Error("Error opening file: %s", path)
		return err
	}
	defer xmlFile.Close()
	data, err := ioutil.ReadAll(xmlFile)
	if err != nil {
		log.Error("Error reading file: %s", path)
		return err
	}
	err = xml.Unmarshal(data, &x)
	if err != nil {
		log.Error("Error unmarshal xml.")
		return err
	}
	return nil
}

func (x *XMLConf) CreateNameNodeConf() (c NameNodeConf) {
	h, err := os.Hostname()
	if err != nil {
		panic(err)
	}
	t, err := net.ResolveIPAddr("ip", h)
	if err != nil {
		panic(err)
	}
	c.ServerIP = t.IP.String()
	// 默认关闭https
	c.HttpsOpen = false
	c.NameService, _ = x.SearchConf("dfs.nameservices")
	d, _ := x.SearchConf("dfs.ha.namenodes." + c.NameService)
	for _, id := range strings.Split(d, ",") {
		r := "dfs.namenode.rpc-address." + c.NameService + "." + id
		if v, _ := x.SearchConf(r); strings.Contains(v, h) {
			c.NameNodeID = id
			d, _ = x.SearchConf(r)
			c.RpcPort = strings.Split(d, ":")[1]
			break
		}
	}
	// 判断是否开启HTTPS，并获取端口
	if v, _ := x.SearchConf("dfs.http.policy"); v == "HTTPS_ONLY" {
		c.HttpsOpen = true
		p, _ := x.SearchConf("dfs.namenode.https-address." + c.NameService + "." + c.NameNodeID)
		c.HttpsPort = strings.Split(p, ":")[1]
	} else {
		p, _ := x.SearchConf("dfs.namenode.http-address." + c.NameService + "." + c.NameNodeID)
		c.HttpPort = strings.Split(p, ":")[1]
	}

	return c
}

func (x *XMLConf) CreateDataNodeConf() (c DataNodeConf) {
	h, err := os.Hostname()
	if err != nil {
		panic(err)
	}
	t, err := net.ResolveIPAddr("ip", h)
	if err != nil {
		panic(err)
	}
	c.HostName = h
	c.ServerIP = t.IP.String()
	// 搜索ipc端口配置
	i, err := x.SearchConf("dfs.datanode.ipc.address")
	c.RpcPort = strings.Split(i, ":")[1]
	if v, err := x.SearchConf("dfs.datanode.address"); err == nil {
		c.ServerPort = strings.Split(v, ":")[1]
	} else {
		c.ServerPort = "50010"
	}
	// 默认关闭https
	c.HttpsOpen = false
	// 判断是否开启HTTPS，并获取端口
	if v, _ := x.SearchConf("dfs.http.policy"); v == "HTTPS_ONLY" {
		c.HttpsOpen = true
		if p, err := x.SearchConf("dfs.datanode.https.address"); err == nil {
			c.HttpsPort = strings.Split(p, ":")[1]
		}
	} else {
		if p, err := x.SearchConf("dfs.datanode.http.address"); err == nil {
			c.HttpPort = strings.Split(p, ":")[1]
		}
	}
	return c
}

func (x *XMLConf) CreateResourceManagerConf() (c ResourceManagerConf) {
	h, err := os.Hostname()
	if err != nil {
		panic(err)
	}
	t, err := net.ResolveIPAddr("ip", h)
	if err != nil {
		panic(err)
	}
	c.ServerIP = t.IP.String()
	// 默认关闭https
	c.HttpsOpen = false
	r, _ := x.SearchConf("yarn.resourcemanager.ha.rm-ids")
	for _, id := range strings.Split(r, ",") {
		r := "yarn.resourcemanager.resource-tracker.address." + id
		// 在yarn.resourcemanager.hostname.rm1 / rm2 中搜索是否存在主机名h，如果有则认为是这个rm，傻逼中兴的平台这里尼玛的又改了，草拟吗
		if v, _ := x.SearchConf(r); strings.Contains(v, h) {
			c.ResourceMangerID = id
			rpc, _ := x.SearchConf(r)
			c.RpcPort = strings.Split(rpc, ":")[1]
			break
		}
	}
	// 判断是否开启HTTPS，并获取端口
	if v, _ := x.SearchConf("yarn.http.policy"); v == "HTTPS_ONLY" {
		c.HttpsOpen = true
		addr, _ := x.SearchConf("yarn.resourcemanager.webapp.https.address." + c.ResourceMangerID)
		c.HttpsPort = strings.Split(addr, ":")[1]
	} else {
		addr, _ := x.SearchConf("yarn.resourcemanager.webapp.address." + c.ResourceMangerID)
		c.HttpPort = strings.Split(addr, ":")[1]
	}
	return c
}
